/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
/*
 * Created on Feb 21, 2006
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package fr.jade.service.fm.reactor;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.ContentController;
import org.objectweb.fractal.api.control.SuperController;

import fr.jade.base.JadeBaseComponent;
import fr.jade.service.fm.deployment.AddSubComponentTask;
import fr.jade.service.fm.deployment.CleanChildTask;
import fr.jade.service.fm.deployment.CleanFatherTask;
import fr.jade.service.fm.deployment.DeploymentTask;
import fr.jade.service.fm.deployment.NewComponentTask;
import fr.jade.util.FractalNavigator;
import fr.jade.util.FractalUtil;
import fr.jade.util.JadeException;

public class ContentPolicy extends JadeBaseComponent implements Policy{

  public int getPriorityLevel(){
    return 2;
  }
  
  public Set<DeploymentTask> execute(Map<Component, NewComponentTask> context, Set<Component> failedCmps_M, Set<Component> impactedCmps_M, Component newNode_M) throws JadeException {
    log("Content Policy");
	  Map<Component, Set<Component>> containmentRelationship = new HashMap<Component, Set<Component>>();
	  for (Component failedCmp_M : failedCmps_M) {
		  addAsFather(containmentRelationship, failedCmp_M);
		  addAsChild(containmentRelationship, failedCmp_M);
		}
		return createTasks(context, containmentRelationship, impactedCmps_M, failedCmps_M);
	}
	
	protected void addAsFather(Map<Component, Set<Component>> containmentRelationship, Component failedCmp_M) {
	  try{
	  ContentController cc_M = FractalUtil.getOptContentController(failedCmp_M);
	  Set<Component> childs_M = new HashSet<Component>();
	  for(Component child_M : cc_M.getFcSubComponents()){
	    childs_M.add(child_M);
	  }
	  containmentRelationship.put(failedCmp_M, childs_M);
	  }catch(NoSuchInterfaceException ignored){
	    // failedCmp_M in not a composite component
	  }
	}
	
	protected void addAsChild(Map<Component, Set<Component>> containmentRelationship, Component failedCmp_M){
    try{
	  SuperController sc_M = FractalUtil.getOptSuperController(failedCmp_M);
    for(Component father_M : sc_M.getFcSuperComponents()){
      if(!containmentRelationship.containsKey(father_M)){
        containmentRelationship.put(father_M, new HashSet<Component>());
      }
      Set<Component> childs = containmentRelationship.get(father_M);
      childs.add(failedCmp_M);
    }
    }catch(NoSuchInterfaceException e){
      // failedCmp_M is a root component 
      // should not occur ??
      log(e);
    }
  }
	
	protected Set<DeploymentTask> createTasks(Map<Component, NewComponentTask> context, Map<Component, Set<Component>> containmentRelationship, Set<Component> impactedCmps_M, Set<Component> failedCmps_M){
	  Set<DeploymentTask> tasks= new HashSet<DeploymentTask>();
	  for(Map.Entry<Component, Set<Component>> entry : containmentRelationship.entrySet()){
	    Component father = entry.getKey();
	    if(impactedCmps_M.contains(father)||failedCmps_M.contains(father)){
  	    NewComponentTask fatherTask = context.get(father);
  	    for(Component child : entry.getValue()){
  	      NewComponentTask childTask = context.get(child);
  	      if(impactedCmps_M.contains(father)){
  	        // remove failed child in impacted father
    	      log(FractalNavigator.getName(father)+ " > " + FractalNavigator.getName(child) + "(clean father)");
            tasks.add(new CleanFatherTask(father, child));
  	      }
  	      if(impactedCmps_M.contains(child)){
  	        // remove failed father in impacted child
  	        log(FractalNavigator.getName(father)+ " > " + FractalNavigator.getName(child) + "(clean child)");
            tasks.add(new CleanChildTask(father, child));
  	      }
  	      log(FractalNavigator.getName(father)+ " > " + FractalNavigator.getName(child));
  	      tasks.add(new AddSubComponentTask(fatherTask, childTask));
  	    }
	    }else{
	      // component is an admin artefact
	      // this should be solved by an architectural view mechanism with authentication
	      // some stuff in perspective ....
	    }
	  }
	  return tasks;
	}
	
}
